package com.atguigu.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.cart.feign.ProductFeignService;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import com.atguigu.gulimall.cart.service.CartService;
import com.atguigu.gulimall.cart.to.UserInfoTo;
import com.atguigu.gulimall.cart.vo.CartItemVo;
import com.atguigu.gulimall.cart.vo.CartVo;
import com.atguigu.gulimall.cart.vo.SkuInfoVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private ProductFeignService productFeignService;

    @Autowired
    private ThreadPoolExecutor executor;


    private final static String CART_PREFIX = "gulimall:cart:";


    @Override
    public CartItemVo addToCart(Long skuId, Integer num) throws ExecutionException, InterruptedException {
        BoundHashOperations<String, Object, Object> hashOps = getCart();

        //加入购物车之前判断是否已经有该商品
        String sku = (String) hashOps.get(skuId.toString());
        if (sku != null) {
            //已经有该商品，直接增加数量
            CartItemVo cartItemVo = JSON.parseObject(sku, CartItemVo.class);
            cartItemVo.setCount(cartItemVo.getCount() + num);

            //修改redis数据
            String s = JSON.toJSONString(cartItemVo);
            hashOps.put(skuId.toString(), s);
            return cartItemVo;
        }
        CartItemVo cartItemVo = new CartItemVo();
        CompletableFuture<Void> infoFuture = CompletableFuture.runAsync(() -> {
            //1.获取sku详情
            R r = productFeignService.getSkuInfo(skuId);
            SkuInfoVo skuInf = r.getData("skuInfo", new TypeReference<SkuInfoVo>() {
            });
            cartItemVo.setCount(num);
            cartItemVo.setImage(skuInf.getSkuDefaultImg());
            cartItemVo.setSkuId(skuId);
            cartItemVo.setTitle(skuInf.getSkuTitle());
            cartItemVo.setPrice(skuInf.getPrice());
        }, executor);
        CompletableFuture<Void> attrFuture = CompletableFuture.runAsync(() -> {
            //获取销售属性组
            List<String> attrStringList = productFeignService.getAttrStringList(skuId);
            cartItemVo.setSkuAttrValues(attrStringList);
        }, executor);

        CompletableFuture.allOf(infoFuture, attrFuture).get();
        //加入redis购物车
        String s = JSON.toJSONString(cartItemVo);
        hashOps.put(skuId.toString(), s);

        return cartItemVo;
    }

    @Override
    public CartItemVo getCartItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cart = getCart();
        String object = (String) cart.get(skuId.toString());
        CartItemVo cartItemVo = null;
        if (object != null) {
            cartItemVo = JSON.parseObject(object, CartItemVo.class);
        }
        return cartItemVo;
    }

    @Override
    public CartVo getCartAndItems() throws ExecutionException, InterruptedException {
        //判断用户是否登录
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        CartVo cartVo = new CartVo();
        if(userInfoTo.getUserId()!=null){
            //用户已经登录
            //先查出临时购物车，再合并两个购物车
            List<CartItemVo> cartItemVos = getCartByKey(CART_PREFIX + userInfoTo.getUserKey());
            if(cartItemVos!=null&&cartItemVos.size()>0){
                for (CartItemVo itemVo : cartItemVos) {
                    addToCart(itemVo.getSkuId(),itemVo.getCount());
                }
                //删除临时购物车
                stringRedisTemplate.delete(CART_PREFIX + userInfoTo.getUserKey());
            }
            //查出最新的用户购物车
            List<CartItemVo> cartByKey = getCartByKey(CART_PREFIX + userInfoTo.getUserId());
            cartVo.setItems(cartByKey);
        }
        else {
            //用户未登录，查询临时购物车
            List<CartItemVo> cartItemVos = getCartByKey(CART_PREFIX + userInfoTo.getUserKey());
            cartVo.setItems(cartItemVos);
        }
        return cartVo;
    }

    @Override
    public void checkItem(Long skuId, Boolean checked) {
        CartItemVo cartItem = getCartItem(skuId);
        cartItem.setCheck(checked);
        //修改redis的数据
        BoundHashOperations<String, Object, Object> cart = getCart();
        cart.put(skuId.toString(),JSON.toJSONString(cartItem));
    }

    @Override
    public void countItem(Long skuId, Integer count) {
        CartItemVo cartItem = getCartItem(skuId);
        cartItem.setCount(count);
        //修改redis的数据
        BoundHashOperations<String, Object, Object> cart = getCart();
        cart.put(skuId.toString(),JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteItem(Long skuId) {
        BoundHashOperations<String, Object, Object> cart = getCart();
        cart.delete(skuId.toString());
    }

    @Override
    public List<CartItemVo> currentMemberCartitems(Long memverId) {
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        if(userInfoTo.getUserId()==null){
            //用户未登录
            return null;
        }
        List<CartItemVo> cartItemVos = getCartByKey(CART_PREFIX + userInfoTo.getUserId());
        //封装最新的被勾选的商品价格
        List<CartItemVo> collect = cartItemVos.stream().filter((item) -> item.getCheck())
                .map((item) -> {
                    BigDecimal price = productFeignService.price(item.getSkuId());
                    item.setPrice(price);
                    return item;
                }).collect(Collectors.toList());
        return collect;
    }

    private List<CartItemVo> getCartByKey(String key) {
        BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps(key);
        List<Object> values = hashOps.values();
        List<CartItemVo> collect = values.stream().map(item -> {
            String json = (String) item;
            CartItemVo cartItemVo = JSON.parseObject(json, CartItemVo.class);
            return cartItemVo;
        }).collect(Collectors.toList());
        return collect;
    }

    private BoundHashOperations<String, Object, Object> getCart() {
        //判断对哪个购物车操作
        UserInfoTo userInfoTo = CartInterceptor.threadLocal.get();
        Long userId = userInfoTo.getUserId();
        String cartName = "";
        if (userId != null) {
            //用户购物车
            cartName = CART_PREFIX + userId;
        } else {
            //临时购物车
            cartName = CART_PREFIX + userInfoTo.getUserKey();
        }
        BoundHashOperations<String, Object, Object> hashOps = stringRedisTemplate.boundHashOps(cartName);
        return hashOps;
    }
}
